package com.gorkr.multi;

import org.junit.jupiter.api.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author gorkr
 * @date 2022/09/17 11:41
 **/
public class M1115PrintFoobarAlternately {

    private int n;
    private final Object lock = new Object();

    private volatile boolean first = true;


    public M1115PrintFoobarAlternately(int n) {
        this.n = n;
    }



    public void foo(Runnable printFoo) throws InterruptedException {

        for (int i = 0; i < n; i++) {

            synchronized (lock) {
                while (!first) {
                    lock.wait();
                }
                // printFoo.run() outputs "foo". Do not change or remove this line.
                printFoo.run();
                first = false;
                lock.notifyAll();
            }

        }
    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {

            synchronized (lock) {
                while (first) {
                    lock.wait();
                }

                // printBar.run() outputs "bar". Do not change or remove this line.
                printBar.run();
                first = true;
                lock.notifyAll();
            }

        }
    }

    public static void main(String[] args) {


        M1115PrintFoobarAlternately m1115PrintFoobarAlternately = new M1115PrintFoobarAlternately(10);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(() -> {
            try {
                m1115PrintFoobarAlternately.foo(() -> {
                    System.out.print("foo");
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        executorService.submit(() -> {
            try {
                m1115PrintFoobarAlternately.bar(() -> {
                    System.out.print("bar");
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }

}
    